package control;

import meterAPI.Communicator;
import Utilities.FileServices;
import communication.Receiver;
import communication.Sender;
import Configuration.Configuration;
import Configuration.Protocol;
import consumption.ConsumptionMeasurement;

/**
 * The Main Controller class which initiates all other componenets. This class
 * runs on a seprate thread than the Reader and ConsumptionMeasurement threads.
 * This runs on an infinite loop until an outage is detected. If there's an
 * outage then all the voltage values stored are written to a file
 * 
 * @author Pavel
 *
 */
public class Controller {
	private Communicator communicator;
	private Sender sender;
	private Receiver receiver;
	private ConsumptionMeasurement consumpMeasure;
	private Configuration configuration;

	public Controller() throws Exception {
		this.communicator = new Communicator("localhost", 5555);
		receiver = new Receiver(this.communicator);
		receiver.start();
		sender = new Sender(this.communicator);
		configuration = new Configuration();
		consumpMeasure = new ConsumptionMeasurement(
				configuration.getAmpValue(), configuration.getHOURS());
		consumpMeasure.start();
		mainLoop();

	}
	
	/**
	 * Returns the on/off status of the SmartMeter
	 * @return
	 */
	public boolean getPowerStatus() {
		return configuration.isPowerOn();
	}
	
	/**
	 * Verifies a message according to the set protocol
	 * @param message
	 * @return true if the message follows the protocol defined. false otherwise
	 */
	public boolean validateMessage(String message) {
		return Protocol.verify(message);
	}
	
	/**
	 * Processes the input message
	 * @param message
	 * @throws Exception
	 */
	public void processCommand(String message) throws Exception {

		String[] splitmessage = message.split("\\$");
		message = splitmessage[0];

		if (message.startsWith("CON") && message.endsWith("All")) {
			sender.send(Protocol.formatAllData(
					Long.toString(configuration.getMeterID()),
					consumpMeasure.getAllConsumptionData()));
		}

		else if (message.startsWith("CON")) {

			String[] splitms = message.split(" ");
			String timeStamp = splitms[2] + " " + splitms[3];
			Double consumption = consumpMeasure.getConsumption(timeStamp);
			String formattedMessage = Protocol.formatSingleData(
					Long.toString(configuration.getMeterID()),
					timeStamp.toString(), consumption);
			sender.send(formattedMessage);
			
		} else if (message.startsWith("SET")) {

			if (message.endsWith("off")) {
				System.out.println("[SmartMeter] Switching off");
				consumpMeasure.setPowerOn(false);
				sender.send(Protocol.formatPoweroffMessage(Long.toString(configuration.getMeterID())));
			} else if (message.endsWith("on")) {
				System.out.println("[SmartMeter] Switching on");
				sender.send(Protocol.formatPowerOnMessage(Long.toString(configuration.getMeterID())));
			}
		}
	}
	
	/**
	 * Writes all the voltage values to a file in case of an outage
	 */
	public void writeDataToFile() {

		FileServices.writeToFile(consumpMeasure.getAllConsumptionData());
	}
	
	/**
	 * Contains all the logic for processing messages received and sending reply.
	 * Runs until an outage is detected
	 * @throws Exception
	 */
	public void mainLoop() throws Exception {

		//System.out.println("[SmartMeter] Sending Hello message");
		//send("Hello this is the meter: " + configuration.getMeterID());

		while (!consumpMeasure.getOutage()) {
			while (!receiver.isMessageQueueEmpty()) {
				String received = receiver.getMessage();
				if (validateMessage(received)) {
					processCommand(received);
				}
				
				else {
					System.out.println("[SmartMeter] Message format not recognized");
				}
			}

		}
		// there is a power outage, so send the outage message
		sender.send(Protocol.formatOutageMessage(Long.toString(configuration.getMeterID())));
		//write the voltage data to file
		writeDataToFile();
		communicator.close();
	}

}
